#include "DXUT.h"

#ifndef REGION_H
#define REGION_H

#include "Chunk.h"
#include "Landmap.h"
#include "zlib.h"

#include <queue>

#define CHUNKCOUNT			4096
#define MAPSIZE				65536

struct SetCallBuffer
{
	int x;
	int z;
	int y;

	char ix;
	char iz;
	char iy;

	Block block;

	byte flags;

	bool operator == (const SetCallBuffer& rhs) const
    {
		return ((x == rhs.x) && (z == rhs.z));
    };

	bool operator < (const  SetCallBuffer& rhs) const
	{
		return ( y < rhs.y)  || (( y == rhs.y) && (( z < rhs.z) || ( z == rhs.z) && (( x < rhs.x))));
	};

	bool operator > (const  SetCallBuffer& rhs) const
	{
		return ( y > rhs.y)  || (( y == rhs.y) && (( z > rhs.z) || ( z == rhs.z) && (( x > rhs.x))));
	};
};

struct Fileheader
{
	uint position;
	uint size;
};

class Region : public IWorld
{
protected:
	// Region-World-Position
	int		_x;
	int		_z;

	// Region-relativ-Position
	int		rx;	
	int		rz;

	int		seed;

	int		loadedCounter;

	IWorld		*pWorld;
	FILE		*file;
	bool		bUseFiles;

	Chunk		**pChunks;
	Biomemap	*m_pBiomemap;
	Landmap		*m_pLandmap;
	byte		*heightmap;

	SRWLOCK					LOCK;

#ifdef RENDER
	CRITICAL_SECTION		dirtyLock;
	queue<int>				dirtychunks;
	CRITICAL_SECTION		imdirtyLock;
	queue<int>				imdirtychunks;
#endif

	vector<SetCallBuffer>	setcalls;

	bool		changed[256];

	void init(IWorld* world, int seed, int x, int z, bool useFiles);

	inline void generateOrePocket(int x, int z, int y, Block block, int size);
	inline Chunk * getChunk(int i);
public:
	/* Region in Regionspace */
	Region(IWorld* world, int seed, int x, int z, bool useFiles = true);
	Region(IWorld* world, int x, int z, bool useFiles = true);
	~Region();

	/* loading in Chunkspace */
	int loadCluster(int x, int z);
	bool unloadCluster(int x, int z, Chunk ** chunks);
	void writeCluster(int x, int z);

	int setCompressedCluster(int x, int z, byte *  memory, uLong   size);
	int getCompressedCluster(int x, int z, byte ** memory, uLong * size);

	void generateStructures(int x, int z, byte *height);

	/* Vertex-methods in Chunkspace */
	void lightPass();
	void lightPass2(int x, int z);
	void lightPass2();
	void lightPass(int x, int z);
	void resetLight();
	void resetLight(int x, int z);

	/* Block-methods in Worldspace */
	Block   getBlock(int x, int z, int y);
	Block * getpBlock(int x, int z, int y);
	Block	breakBlock(int x, int z, int y);
	void setBlock(int x, int z, int y, Block block, byte flags = UPDATE_ALL);
	void update();
	byte updateBlock(int x, int z, int y, byte type, byte * ticks);
	void delayedUpdateBlock(int x, int z, int y, byte type, byte ticks);

	float getTemperature(int x, int z);
	float getHumidity(int x, int z);
	BYTE  getBiome(int x, int z);

#ifdef RENDER
	/* Dirty-methods in Worldspace */
	void setDirty(int x, int z, int y, bool immediatly);
	void renewDirty(ID3D11Device* pd3dDevice, ID3D11DeviceContext* context, bool immediatly);

	/* Vertex-methods in Chunkspace */
	void generateVB(ID3D11Device* pd3dDevice, ID3D11DeviceContext* context);
	void generateVB(ID3D11Device* pd3dDevice, ID3D11DeviceContext* context, int x, int z);
	void Release();
	void Release(int x, int z);

	void render(const D3DXFRUSTUM frustum, ID3D11DeviceContext* pImmediateContext, int index);
#endif
};

#endif